package pl.makimo.ksr.gui;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;

import pl.makimo.data.WeatherRecord;
import pl.makimo.fuzzy.linguistics.Quantifier;
import pl.makimo.fuzzy.linguistics.SummaryFactory;
import pl.makimo.fuzzy.norms.MaxNorm;
import pl.makimo.fuzzy.norms.MinNorm;
import pl.makimo.fuzzy.norms.Norm;
import pl.makimo.fuzzy.norms.Type2MinMaxProductNorm;
import pl.makimo.fuzzy.norms.Type2MinMaxSumNorm;
import pl.makimo.fuzzy.sets.ContinuousFuzzySet;
import pl.makimo.fuzzy.sets.CrispSet;
import pl.makimo.fuzzy.sets.FuzzySet;

public class MainWindow {
	public JFrame frame;
	public JPanel variablesPanel;
	public JPanel summaryPanel;
	public JPanel resultsPanel;
	public JPanel quantifierPanel;
	
	public JTable resultsTable;
	
	public JTextField[] weights = new JTextField[] { new JTextField(), new JTextField(), new JTextField(), new JTextField(), new JTextField(), new JTextField(), new JTextField(), new JTextField(), new JTextField(), new JTextField(), new JTextField() }; 
	
	final public DefaultListModel qualifiersListModel = new DefaultListModel();
	final public DefaultListModel summarizersListModel = new DefaultListModel();
	final public DefaultListModel quantifierListModel = new DefaultListModel();
	final public SummaryTableModel resultsTableModel = new SummaryTableModel();
	
	public JTabbedPane tabbedPane;
	
	final public HashMap<String, LinguisticVariablePanel> variables = new HashMap<String, LinguisticVariablePanel>();
	final public HashMap<String, Quantifier> quantifiers = new HashMap<String, Quantifier>();
	
	final CrispSet<WeatherRecord> tuples = WeatherRecord.getFromFile("C:\\repos\\uczelnia\\ksr-gobbledygook\\weatherdb.csv");
	
	final public HashMap<String, Norm> type1Norms = new HashMap<String, Norm>() {{
		put("MinNorm", new MinNorm());
		put("MaxNorm", new MaxNorm());
	}};

	final public HashMap<String, Norm> type2Norms = new HashMap<String, Norm>() {{
		put("Type2MinMaxSumNorm", new Type2MinMaxSumNorm());
		put("Type2MinMaxProductNorm", new Type2MinMaxProductNorm());
	}};
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					MainWindow window = new MainWindow();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public MainWindow() {
		initialize();
	}

	public void addLinguisticPanel(String name, CrispSet<WeatherRecord> list) {
		LinguisticVariablePanel panel = new LinguisticVariablePanel(name, list);
		variables.put(name, panel);
		variablesPanel.add(panel);
	}
	
	public JPanel createVariableListPanel(String name, final DefaultListModel listModel) {
		JPanel variablePanel = new JPanel();
		variablePanel.setLayout(new BoxLayout(variablePanel, BoxLayout.Y_AXIS));
		
		variablePanel.add(new JLabel(name));
		
		final JList variableListBox = new JList(listModel);
		variableListBox.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		variableListBox.setVisibleRowCount(-1);
		
		JScrollPane qualifiersScroller = new JScrollPane(variableListBox);
		qualifiersScroller.setPreferredSize(new Dimension(250, 80));		
		
		variablePanel.add(qualifiersScroller);
		
		final JComboBox variableComboList = new JComboBox(variables.keySet().toArray());
		variablePanel.add(variableComboList);
		
		JButton addButton = new JButton("Add");
		addButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (!listModel.contains(variableComboList.getSelectedItem().toString())) {
					listModel.addElement(variableComboList.getSelectedItem().toString());
				}
			}
		});
		variablePanel.add(addButton);
		
		JButton deleteButton = new JButton("Delete");
		deleteButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				listModel.removeElement(variableListBox.getSelectedValue());
			}
		});
		variablePanel.add(deleteButton);		
		
		return variablePanel;
	}
	
	public JPanel createNormsPanel() {
		JPanel normsPanel = new JPanel();
		normsPanel.setLayout(new BoxLayout(normsPanel, BoxLayout.Y_AXIS));
		
		/* Norm combos */
		normsPanel.add(new JLabel("Norm for joining type 1 qualifiers"));

		final JComboBox type1QualifierNormCombo = new JComboBox(type1Norms.keySet().toArray());
		normsPanel.add(type1QualifierNormCombo);

		normsPanel.add(new JLabel("Norm for joining type 1 summarizers"));

		final JComboBox type1SummarizerNormCombo = new JComboBox(type1Norms.keySet().toArray());
		normsPanel.add(type1SummarizerNormCombo);
		
		normsPanel.add(new JLabel("Norm for joining type 2 qualifiers"));

		final JComboBox type2QualifierNormCombo = new JComboBox(type2Norms.keySet().toArray());
		normsPanel.add(type2QualifierNormCombo);

		normsPanel.add(new JLabel("Norm for joining type 2 summarizers"));

		final JComboBox type2SummarizerNormCombo = new JComboBox(type2Norms.keySet().toArray());
		normsPanel.add(type2SummarizerNormCombo);		
		
		/* Execute button */
		JButton executeButton = new JButton("Execute summaries");
		executeButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				/* Add variables */
				Set<String> variableSet = new HashSet<String>();
				
				SummaryFactory.clear();
				
				for (Object q : qualifiersListModel.toArray()) {
					variableSet.add(q.toString());
					SummaryFactory.qualifiers.add(q.toString());
				}
				
				for (Object q : summarizersListModel.toArray()) {
					variableSet.add(q.toString());
					SummaryFactory.summarizers.add(q.toString());
				}
				
				for (String s : variableSet) {
					SummaryFactory.addVariable(variables.get(s).variable);
				}
				
				SummaryFactory.qualifiersNorm = type1Norms.get(type1QualifierNormCombo.getSelectedItem());
				SummaryFactory.summarizersNorm = type1Norms.get(type1SummarizerNormCombo.getSelectedItem());
				SummaryFactory.type2qualifiersNorm = type2Norms.get(type2QualifierNormCombo.getSelectedItem());
				SummaryFactory.type2summarizersNorm = type2Norms.get(type2SummarizerNormCombo.getSelectedItem());
				
				for (Quantifier q : quantifiers.values()) {
					SummaryFactory.addQuantifier(q);
				}
				
				int i = 0;
				
				for (JTextField field : weights) {
					SummaryFactory.weights[i] = Double.parseDouble(field.getText());
					i++;
				}
				
				SummaryFactory.executeSummaries();
				
				resultsTableModel.dataChanged();
			}
		});
		normsPanel.add(executeButton);		
		
		return normsPanel;
	}
	
	public JPanel createWeightsPanel() {
		JPanel weightsPanel = new JPanel();
		weightsPanel.setLayout(new BoxLayout(weightsPanel, BoxLayout.Y_AXIS));
		
		int i = 1;
		for (JTextField field : weights) {
			weightsPanel.add(new JLabel("Weight for T" + i + ":"));
			field.setText("1");
			weightsPanel.add(field);
			i++;
		}
		
		return weightsPanel;
	}		
	
	public JPanel createSummaryPanel() {
		JPanel summaryPanel = new JPanel();
		summaryPanel.setLayout(new BoxLayout(summaryPanel, BoxLayout.X_AXIS));
		
		/* Qualifiers */
		summaryPanel.add(createVariableListPanel("Qualifiers", qualifiersListModel));

		/* Summarizers */
		summaryPanel.add(createVariableListPanel("Summarizers", summarizersListModel));
		
		/* Weights */
		summaryPanel.add(createWeightsPanel());
		
		/* Norms and GO FOR IT button */
		summaryPanel.add(createNormsPanel());
		
		return summaryPanel;
	}
	
	public JPanel createResultsPanel() {
		final JPanel resultsPanel = new JPanel();
		resultsPanel.setLayout(new BoxLayout(resultsPanel, BoxLayout.Y_AXIS));
		
		resultsTable = new JTable(resultsTableModel);
		resultsTable.setAutoCreateRowSorter(true);
		
		JScrollPane scrollPane = new JScrollPane(resultsTable);
		resultsTable.setFillsViewportHeight(true);
		
		resultsPanel.add(scrollPane);
		
		final JFileChooser fc = new JFileChooser();
		
		JButton saveButton = new JButton("Save results");
		saveButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				int returnVal = fc.showOpenDialog(resultsPanel);

		        if (returnVal == JFileChooser.APPROVE_OPTION) {
		            File file = fc.getSelectedFile();
		            SummaryFactory.writeToFile(file.getAbsolutePath());
		        }
				
			}
		});
		resultsPanel.add(saveButton);					
		
		return resultsPanel;
	}	
	
	public void addQuantifier(FuzzySet<Double> set, String name, boolean relative) {
		if (!quantifiers.containsKey(name)) {
			quantifiers.put(name, Quantifier.make((ContinuousFuzzySet)set, name, tuples, relative));
			quantifierListModel.addElement(name);
		}
	}	
	
	public JButton createQuantifierSetButton(final Class<?> fuzzysetCreator, String title) {
		JButton b1 = new JButton(title);
	    b1.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {				
				try {
					final FuzzySetCreator creator = (FuzzySetCreator)fuzzysetCreator.newInstance();
					creator.enableRelativeCheckbox();
					creator.setAction(new ActionListener() {
						
						@Override
						public void actionPerformed(ActionEvent e) {
							System.out.println(creator.relative.isSelected());
							addQuantifier(creator.getFuzzySet(), creator.getName(), creator.relative.isSelected());
						}
					});
					creator.show();					
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});		
	    
	    return b1;
	}		
	
	public JPanel createQuantifierPanel() {
		JPanel quantifierPanel = new JPanel();
		quantifierPanel.setLayout(new BoxLayout(quantifierPanel, BoxLayout.Y_AXIS));
		
		final JList nameList = new JList(quantifierListModel);
		nameList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		nameList.setVisibleRowCount(-1);
		
		JScrollPane listScroller = new JScrollPane(nameList);
		listScroller.setPreferredSize(new Dimension(250, 80));		
	
		quantifierPanel.add(listScroller);
		quantifierPanel.add(createQuantifierSetButton(ContinuousType1FuzzySetCreator.class, "New quantifier fuzzy set"));
		
		JButton deleteButton = new JButton("Delete");
		deleteButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				quantifierListModel.removeElement(nameList.getSelectedValue());
				quantifiers.remove(nameList.getSelectedValue());
			}
		});
		quantifierPanel.add(deleteButton);			
		
		return quantifierPanel;
	}		
	
	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		variablesPanel = new JPanel();
		variablesPanel.setLayout(new BoxLayout(variablesPanel, BoxLayout.X_AXIS));

		addLinguisticPanel("time", tuples);
		addLinguisticPanel("temperature", tuples);
		addLinguisticPanel("dew", tuples);
		addLinguisticPanel("humidity", tuples);
		addLinguisticPanel("pressure", tuples);
		addLinguisticPanel("visibility", tuples);
		addLinguisticPanel("wind_speed", tuples);
		addLinguisticPanel("wind_dir", tuples);
		
		summaryPanel = createSummaryPanel();
		
		resultsPanel = createResultsPanel();
		
		quantifierPanel = createQuantifierPanel();
		
		tabbedPane = new JTabbedPane();
		tabbedPane.addTab("Quantifier", quantifierPanel);
		tabbedPane.addTab("Variables", variablesPanel);
		tabbedPane.addTab("Summary", summaryPanel);
		tabbedPane.addTab("Results", resultsPanel);
		
		
	    frame.setContentPane(tabbedPane);
	}
}
